package sg.edu.nus.iss.cats.dataaccess.mysql;

import sg.edu.nus.iss.cats.dataaccess.*;
import sg.edu.nus.iss.cats.model.*;

import java.util.*;

public class CourseDAOImpl implements CourseDAO {

    // private static final String tableName = DBConstants.coursesTableName;

    public Course findCourse (String courseId)
                        throws DAOException {
        CourseSelectionCriteria criteria
                         = new CourseSelectionCriteria ();
        criteria.setCourseId (courseId);
        Course[] results = findCourses (criteria);
        if (results.length == 0) {
            return null;
        }
        return (results[0]);
    }

    public Course[] findCoursesByEmployee (String employeeId)
                        throws DAOException {
        CourseSelectionCriteria criteria = new CourseSelectionCriteria ();
        criteria.setEmployeeId (employeeId);
        Course[] results = findCourses (criteria);
        return results;
    }

    private static final String[] pendingStatuses = {
                                         Course.SUBMITTED,
                                         Course.UPDATED
                                         };
                                         
    public Course[] findCoursesPendingByEmployee (String employeeId)
                        throws DAOException {
        CourseSelectionCriteria criteria = new CourseSelectionCriteria ();
        criteria.setEmployeeId (employeeId);
        criteria.setStatuses (pendingStatuses);
        Course[] results = findCourses (criteria);
        return results;
    }

    public void insertCourse (Course course)
                        throws DAOException {
        SQLObjectManager mgr = new SQLObjectManager (new CourseObjectHandler ());
        mgr.createObject (course);
    }

    public void updateCourse (Course course)
                        throws DAOUpdateException {
        try {
            SQLObjectManager mgr = new SQLObjectManager (
            new CourseObjectHandler ());
            mgr.updateObject (course);
        } catch (DAOException e) {
            throw new DAOUpdateException (e.toString());
        }
    }

    public void deleteCourse (Course course)
                        throws DAOException {
        throw new DAOException ("Not yet implemented!");
    }

    public void insertCourseEvent (CourseEvent event)
                        throws DAOException {
        SQLObjectManager mgr = new SQLObjectManager (new CourseEventObjectHandler ());
        mgr.createObject (event);
    }

    public void updateCourseEvent (CourseEvent event)
                        throws DAOUpdateException {
        try {
            SQLObjectManager mgr = new SQLObjectManager (
            new CourseEventObjectHandler ());
            mgr.updateObject (event);
        } catch (DAOException e) {
            throw new DAOUpdateException (e.toString());
        }
    }

    public void deleteCourseEvent (CourseEvent event)
                        throws DAOException {
        throw new DAOException ("Not yet implemented!");
    }



    private Course[] findCourses (CourseSelectionCriteria criteria)
                        throws DAOException {
        SQLObjectManager mgr = new SQLObjectManager (
            new CourseObjectHandler ());
        mgr.setQueryConstraint (makeQueryContraints (criteria));
        Course[] result = (Course[]) mgr.getObjects ();
        return (result);
    }

    private String makeQueryContraints (CourseSelectionCriteria criteria)
                        throws DAOException {
        Vector v = new Vector ();
        v.add (getValueListConstraints (DBConstants.c_courseId, criteria.getCourseIds(), false));
        v.add (getValueListConstraints (DBConstants.c_employeeId, criteria.getEmployeeIds(), true));
        v.add (getValueListConstraints (DBConstants.c_organiser, criteria.getOrganisers(), true));
        v.add (getConstraint (">=", DBConstants.c_toDate, criteria.getPeriodStart(), false));
        v.add (getConstraint ("<=", DBConstants.c_fromDate, criteria.getPeriodEnd(), false));
        v.add (getValueListConstraints (DBConstants.c_status, criteria.getStatuses(), true));
        return joinConstraints (v, "AND");
    }

    private String getValueListConstraints (String fieldName,
                    Object[] values, boolean quote) {
        if (values == null) {
            return null;
        }
        Vector v = new Vector ();
        for (int i = 0; i < values.length; i++) {
            v.add (getConstraint ("=", fieldName, values[i], quote));
        }
        return joinConstraints (v, "OR");
    }

    private String getConstraint (String operator, String fieldName,
                Object value, boolean quote) {
        if (value == null) {
            return null;
        }
        String valueString = value.toString();
        if (quote) {
            valueString  = "'" + valueString + "'";
        }
        String s = "(" + fieldName + operator + valueString + ")";
        return s;
    }

    private String joinConstraints (Collection c, String logicalOp) {
        String result = null;
        boolean parenthesis = false;
        Iterator i = c.iterator ();
        while (i.hasNext()) {
            String s = (String) i.next ();
            if (s == null) {
                continue;
            }
            if (result != null) {
                result += " " + logicalOp + " " + s;
                parenthesis = true;
            } else {
                result = s;
            }
        }
        if (parenthesis) {
           result = "(" + result + ")";
        }
        return result;
    }

}


